package drds.data_propagate.task.manager.model;

import drds.data_propagate.common.utils.ToStringStyle;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

/**
 * 任务运行相关参数
 */
public class Parameter implements Serializable {

    private static final long serialVersionUID = -5893459662315430900L;
    @Setter
    @Getter
    private Long canalId;

    // 相关参数


    @Setter
    @Getter
    private Long zkClusterId; // zk集群id，为管理方便
    @Setter
    @Getter
    private List<String> zkClusters; // zk集群地址
    @Setter
    @Getter
    private String dataDir = "../conf"; // 默认本地文件数据的目录默认是conf

    @Setter
    @Getter
    private Integer metaFileFlushPeriod = 1000; // meta刷新间隔

    // storage存储
    @Setter
    @Getter
    private Integer transactionSize = 1024; // 支持处理的transaction事务大小


    @Setter
    @Getter
    private Integer memoryStorageBufferSize = 16 * 1024; // 内存存储的buffer大小
    @Setter
    @Getter
    private Integer memoryStorageBufferMemUnit = 1024; // 内存存储的buffer内存占用单位，默认为1kb
    @Setter
    @Getter
    private Boolean memoryStorageRawEntry = Boolean.TRUE; // 内存存储的对象是否启用raw的ByteString模式
    @Setter
    @Getter
    private String fileStorageDirectory; // 文件存储的目录位置
    @Setter
    @Getter
    private Integer fileStorageStoreCount; // 每个文件store存储的记录数
    @Setter
    @Getter
    private Integer fileStorageRollverCount; // store文件的个数
    @Setter
    @Getter
    private Integer fileStoragePercentThresold; // 整个store存储占disk硬盘的百分比，超过百分比及时条数还未满也不写入
    @Setter
    @Getter
    private StorageScavengeMode storageScavengeMode = StorageScavengeMode.ON_ACK;
    @Setter
    @Getter
    private String scavengeSchdule; // 调度规则

    // replcation相关参数
    @Setter
    @Getter
    private BinlogEventParserType binlogEventParserType = BinlogEventParserType.db; // 数据来源类型
    @Setter
    @Getter
    private String localBinlogDirectory; // 本地localBinlog目录

    // 网络链接参数
    @Setter
    @Getter
    private Integer port = 11111; // 服务端口，独立运行时需要配置
    @Setter
    @Getter
    private Integer defaultConnectionTimeoutInSeconds = 30; // sotimeout
    @Setter
    @Getter
    private Integer receiveBufferSize = 64 * 1024;
    @Setter
    @Getter
    private Integer sendBufferSize = 64 * 1024;
    // 编码信息
    @Setter
    @Getter
    private Byte connectionCharsetNumber = (byte) 33;
    @Setter
    @Getter
    private String connectionCharset = "UTF-8";

    // 数据库信息
    @Setter
    @Getter
    private List<InetSocketAddress> dbAddresses; // 数据库链接信息
    @Setter
    @Getter
    private List<List<DataSourcing>> groupDbAddresses; // 数据库链接信息，包含多组信息
    @Setter
    @Getter
    private String dbUsername; // 数据库用户
    @Setter
    @Getter
    private String dbPassword; // 数据库密码

    // binlog链接信息
    @Setter
    @Getter
    private IndexMode indexMode = IndexMode.MEMORY;
    @Setter
    @Getter
    private List<String> positions; // 数据库positions信息
    @Setter
    @Getter
    private String defaultDatabaseName; // 默认链接的数据库schmea
    @Setter
    @Getter
    private Long slaveId; // 链接到mysql的slaveId
    @Setter
    @Getter
    private Integer fallbackIntervalInSeconds = 60; // 数据库发生切换查找时回退的时间

    // 心跳检查信息
    @Setter
    @Getter
    private Boolean detectingEnable = true; // 是否开启心跳语句
    @Setter
    @Getter
    private Boolean heartbeatHaEnable = false; // 是否开启基于心跳检查的ha功能
    @Setter
    @Getter
    private String detectingSQL; // 心跳sql
    @Setter
    @Getter
    private Integer detectingIntervalInSeconds = 3; // 检测频率
    @Setter
    @Getter
    private Integer detectingTimeoutThresholdInSeconds = 30; // 心跳超时时间
    @Setter
    @Getter
    private Integer detectingRetryTimes = 3; // 心跳检查重试次数

    // tddl/diamond 配置信息
    @Setter
    @Getter
    private String app;
    @Setter
    @Getter
    private String group;
    // media配置信息
    @Setter
    @Getter
    private String mediaGroup;
    // metaq 存储配置信息
    @Setter
    @Getter
    private String metaqStoreUri;

    // ddl同步支持，隔离dml/ddl
    @Setter
    @Getter
    private Boolean ddlIsolation = Boolean.FALSE; // 是否将ddl单条返回
    @Setter
    @Getter
    private Boolean filterTableError = Boolean.FALSE; // 是否忽略表解析异常
    @Setter
    @Getter
    private String blackFilter = null; // 匹配黑名单,忽略解析
    @Setter
    @Getter
    private Boolean tsdbEnable = Boolean.FALSE; // 是否开启tableMetaTSDB
    @Setter
    @Getter
    private String tsdbJdbcUrl;
    @Setter
    @Getter
    private String tsdbJdbcUserName;
    @Setter
    @Getter
    private String tsdbJdbcPassword;
    @Setter
    @Getter
    private Integer tsdbSnapshotInterval = 24;
    @Setter
    @Getter
    private Integer tsdbSnapshotExpire = 360;
    @Setter
    @Getter
    private String rdsAccesskey;
    @Setter
    @Getter
    private String rdsSecretkey;
    @Setter
    @Getter
    private String rdsInstanceId;
    @Setter
    @Getter
    private Boolean gtidEnable = Boolean.FALSE; // 是否开启gtid

    // ================================== 兼容字段处理
    @Setter
    @Getter
    private InetSocketAddress masterAddress; // 主库信息
    @Setter
    @Getter
    private String masterUsername; // 帐号
    @Setter
    @Getter
    private String masterPassword; // 密码
    @Setter
    @Getter
    private InetSocketAddress standbyAddress; // 备库信息
    @Setter
    @Getter
    private String standbyUsername; // 帐号
    @Setter
    @Getter
    private String standbyPassword;
    @Setter
    @Getter
    private String masterLogfileName = null; // master起始位置
    @Setter
    @Getter
    private Long masterLogfileOffest = null;
    @Setter
    @Getter
    private Long masterTimestamp = null;
    @Setter
    @Getter
    private String standbyLogfileName = null; // standby起始位置
    @Setter
    @Getter
    private Long standbyLogfileOffest = null;
    @Setter
    @Getter
    private Long standbyTimestamp = null;
    @Setter
    @Getter
    private Boolean parallel = Boolean.FALSE;

    // 自定义alarmHandler类全路径
    @Setter
    @Getter
    private String alarmHandlerClass = null;
    @Setter
    @Getter
    // 自定义alarmHandler插件文件夹路径
    private String alarmHandlerPluginDir = null;


    public List<InetSocketAddress> getDbAddresses() {
        if (dbAddresses == null) {
            dbAddresses = new ArrayList<InetSocketAddress>();
            if (masterAddress != null) {
                dbAddresses.add(masterAddress);
            }

            if (standbyAddress != null) {
                dbAddresses.add(standbyAddress);
            }
        }
        return dbAddresses;
    }

    public void setDbAddresses(List<InetSocketAddress> dbAddresses) {
        this.dbAddresses = dbAddresses;
    }

    public List<List<DataSourcing>> getGroupDbAddresses() {
        if (groupDbAddresses == null) {
            groupDbAddresses = new ArrayList<List<DataSourcing>>();
            if (dbAddresses != null) {
                for (InetSocketAddress address : dbAddresses) {
                    List<DataSourcing> groupAddresses = new ArrayList<DataSourcing>();
                    groupAddresses.add(new DataSourcing(binlogEventParserType, address));
                    groupDbAddresses.add(groupAddresses);
                }
            } else {
                if (masterAddress != null) {
                    List<DataSourcing> groupAddresses = new ArrayList<DataSourcing>();
                    groupAddresses.add(new DataSourcing(binlogEventParserType, masterAddress));
                    groupDbAddresses.add(groupAddresses);
                }

                if (standbyAddress != null) {
                    List<DataSourcing> groupAddresses = new ArrayList<DataSourcing>();
                    groupAddresses.add(new DataSourcing(binlogEventParserType, standbyAddress));
                    groupDbAddresses.add(groupAddresses);
                }
            }
        }
        return groupDbAddresses;
    }

    public void setGroupDbAddresses(List<List<DataSourcing>> groupDbAddresses) {
        this.groupDbAddresses = groupDbAddresses;
    }

    public String getDbUsername() {
        if (dbUsername == null) {
            dbUsername = (masterUsername != null ? masterUsername : standbyUsername);
        }
        return dbUsername;
    }

    public void setDbUsername(String dbUsername) {
        this.dbUsername = dbUsername;
    }

    public String getDbPassword() {
        if (dbPassword == null) {
            dbPassword = (masterPassword != null ? masterPassword : standbyPassword);
        }
        return dbPassword;
    }

    public void setDbPassword(String dbPassword) {
        this.dbPassword = dbPassword;
    }

    public List<String> getPositions() {
        if (positions == null) {
            positions = new ArrayList<String>();
            String masterPosition = buildPosition(masterLogfileName, masterLogfileOffest, masterTimestamp);
            if (masterPosition != null) {
                positions.add(masterPosition);
            }

            String standbyPosition = buildPosition(standbyLogfileName, standbyLogfileOffest, standbyTimestamp);
            if (standbyPosition != null) {
                positions.add(standbyPosition);
            }

        }
        return positions;
    }

    public void setPositions(List<String> positions) {
        this.positions = positions;
    }

    private String buildPosition(String journalName, Long position, Long timestamp) {
        StringBuilder masterBuilder = new StringBuilder();
        if (StringUtils.isNotEmpty(journalName) || position != null || timestamp != null) {
            masterBuilder.append('{');
            if (StringUtils.isNotEmpty(journalName)) {
                masterBuilder.append("\"binlogEventFileName\":\"").append(journalName).append("\"");
            }

            if (position != null) {
                if (masterBuilder.length() > 1) {
                    masterBuilder.append(",");
                }
                masterBuilder.append("\"readedIndex\":").append(position);
            }

            if (timestamp != null) {
                if (masterBuilder.length() > 1) {
                    masterBuilder.append(",");
                }
                masterBuilder.append("\"executeTimestamp\":").append(timestamp);
            }
            masterBuilder.append('}');
            return masterBuilder.toString();
        } else {
            return null;
        }
    }


    public String toString() {
        return ToStringStyle.toString(this);
    }


}
